ioemu: sdl blitting
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 3 Mar 2008 11:06:31 +0000 (11:06 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 3 Mar 2008 11:06:31 +0000 (11:06 +0000)
Right now qemu takes care of converting pixels between the guest pixel
format and the sdl pixel format, after that qemu also memcpy the
converted pixels to the sdl buffer in video ram. This process can be
improved using the SDL blit capabilities: the patch I am attaching
creates an SDL Surface from the Cirrus VGA framebuffer and uses SDL
blitting functions to convert and write pixels to video ram. SDL
blitting functions are optimized and can even be hardware accelerated
on some platforms.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
tools/ioemu/hw/vga.c
tools/ioemu/sdl.c
tools/ioemu/vl.h
tools/ioemu/vnc.c

index 7c627166422d6f6a750a59c074fb03612814100c..fb6595d9d76b1776062314b3a934d5ef554fe84d 100644 (file)
@@ -1481,7 +1481,7 @@ void check_sse2(void)
 static void vga_draw_graphic(VGAState *s, int full_update)
 {
     int y1, y, update, linesize, y_start, double_scan, mask, depth;
-    int width, height, shift_control, line_offset, bwidth;
+    int width, height, shift_control, line_offset, bwidth, changed_flag;
     ram_addr_t page0, page1;
     int disp_width, multi_scan, multi_run;
     uint8_t *d;
@@ -1554,10 +1554,12 @@ static void vga_draw_graphic(VGAState *s, int full_update)
     }
     vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
 
+    changed_flag = 0;
     depth = s->get_bpp(s);
-    if (s->ds->dpy_colourdepth != NULL && s->ds->depth != depth) {
-        if (depth != 24 || s->ds->depth != 32)
-            s->ds->dpy_colourdepth(s->ds, depth);
+    if (s->ds->dpy_colourdepth != NULL && 
+            (s->ds->depth != depth || !s->ds->shared_buf)) {
+        s->ds->dpy_colourdepth(s->ds, depth);
+        changed_flag = 1;
     }
     if (disp_width != s->last_width ||
         height != s->last_height) {
@@ -1567,9 +1569,10 @@ static void vga_draw_graphic(VGAState *s, int full_update)
         s->last_width = disp_width;
         s->last_height = height;
         full_update = 1;
+        changed_flag = 1;
     }
-    if (s->ds->shared_buf && s->ds->data != s->vram_ptr + (s->start_addr * 4))
-        s->ds->data = s->vram_ptr + (s->start_addr * 4);
+    if (s->ds->shared_buf && (changed_flag || s->ds->data != s->vram_ptr + (s->start_addr * 4)))
+        s->ds->dpy_setdata(s->ds, s->vram_ptr + (s->start_addr * 4));
     if (!s->ds->shared_buf && s->cursor_invalidate)
         s->cursor_invalidate(s);
     
index 4d09469858d6ad9f58662b0f679a32e5bdcedcf2..2f6701e254d2685d294e8af709387aa9e4e26eec 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 static SDL_Surface *screen;
+static SDL_Surface *shared = NULL;
 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
 static int last_vm_running;
 static int gui_saved_grab;
@@ -47,7 +48,46 @@ static int absolute_enabled = 0;
 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 {
     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-    SDL_UpdateRect(screen, x, y, w, h);
+    if (shared) {
+        SDL_Rect rec;
+        rec.x = x;
+        rec.y = y;
+        rec.w = w;
+        rec.h = h;
+        SDL_BlitSurface(shared, &rec, screen, &rec);
+    }
+    SDL_Flip(screen);
+}
+
+static void sdl_setdata(DisplayState *ds, void *pixels)
+{
+    uint32_t rmask, gmask, bmask, amask = 0;
+    switch (ds->depth) {
+        case 8:
+            rmask = 0x000000E0;
+            gmask = 0x0000001C;
+            bmask = 0x00000003;
+            break;
+        case 16:
+            rmask = 0x0000F800;
+            gmask = 0x000007E0;
+            bmask = 0x0000001F;
+            break;
+        case 24:
+            rmask = 0x00FF0000;
+            gmask = 0x0000FF00;
+            bmask = 0x000000FF;
+            break;
+        case 32:
+            rmask = 0x00FF0000;
+            gmask = 0x0000FF00;
+            bmask = 0x000000FF;
+            break;
+        default:
+            return;
+    }
+    shared = SDL_CreateRGBSurfaceFrom(pixels, width, height, ds->depth, ds->linesize, rmask , gmask, bmask, amask);
+    ds->data = pixels;
 }
 
 static void sdl_resize(DisplayState *ds, int w, int h)
@@ -56,7 +96,7 @@ static void sdl_resize(DisplayState *ds, int w, int h)
 
     //    printf("resizing to %d %d\n", w, h);
 
-    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
+    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE;
     if (gui_fullscreen)
         flags |= SDL_FULLSCREEN;
 
@@ -78,16 +118,28 @@ static void sdl_resize(DisplayState *ds, int w, int h)
         fprintf(stderr, "Could not open SDL display\n");
         exit(1);
     }
-    ds->data = screen->pixels;
-    ds->linesize = screen->pitch;
-    ds->depth = screen->format->BitsPerPixel;
-    if (ds->depth == 32 && screen->format->Rshift == 0) {
-        ds->bgr = 1;
-    } else {
-        ds->bgr = 0;
-    }
     ds->width = w;
     ds->height = h;
+    if (!ds->shared_buf) {
+        ds->depth = screen->format->BitsPerPixel;
+        if (ds->depth == 32 && screen->format->Rshift == 0) {
+            ds->bgr = 1;
+        } else {
+            ds->bgr = 0;
+        }
+        ds->data = screen->pixels;
+        ds->linesize = screen->pitch;
+    } else {
+        ds->linesize = (ds->depth / 8) * w;
+    }
+}
+
+static void sdl_colourdepth(DisplayState *ds, int depth)
+{
+    if (!depth || !ds->depth) return;
+    ds->shared_buf = 1;
+    ds->depth = depth;
+    ds->linesize = width * depth / 8; 
 }
 
 /* generic keyboard conversion */
@@ -508,7 +560,8 @@ void sdl_display_init(DisplayState *ds, int full_screen)
     ds->dpy_update = sdl_update;
     ds->dpy_resize = sdl_resize;
     ds->dpy_refresh = sdl_refresh;
-    ds->dpy_colourdepth = NULL;
+    ds->dpy_colourdepth = sdl_colourdepth;
+    ds->dpy_setdata = sdl_setdata;
 
     sdl_resize(ds, 640, 400);
     sdl_update_caption();
index 5c421cff9c7e2f209b7491bed6cef8769d793244..66e4ded2d34641cd8392dee7727a8ca2c4429b6b 100644 (file)
@@ -942,6 +942,7 @@ struct DisplayState {
     void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
     void (*dpy_resize)(struct DisplayState *s, int w, int h);
     void (*dpy_colourdepth)(struct DisplayState *s, int depth);
+    void (*dpy_setdata)(DisplayState *ds, void *pixels);
     void (*dpy_refresh)(struct DisplayState *s);
     void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h);
 };
index e14fb617503fa8533af225c0f1bc3d636b485f1e..2c7ee6929f64b326171cac2b7a5913883b890a68 100644 (file)
@@ -1621,6 +1621,11 @@ static void pixel_format_message (VncState *vs) {
     vnc_write(vs, pad, 3);           /* padding */
 }
 
+static void vnc_dpy_setdata(DisplayState *ds, void *pixels)
+{
+    ds->data = pixels;
+}
+
 static void vnc_dpy_colourdepth(DisplayState *ds, int depth)
 {
     int host_big_endian_flag;
@@ -1628,6 +1633,7 @@ static void vnc_dpy_colourdepth(DisplayState *ds, int depth)
 
     switch (depth) {
         case 24:
+            if (ds->depth == 32) return;
             ds->shared_buf = 0;
             depth = 32;
             break;
@@ -2480,6 +2486,7 @@ void vnc_display_init(DisplayState *ds)
     vs->ds->dpy_update = vnc_dpy_update;
     vs->ds->dpy_resize = vnc_dpy_resize;
     vs->ds->dpy_colourdepth = vnc_dpy_colourdepth;
+    vs->ds->dpy_setdata = vnc_dpy_setdata;
     vs->ds->dpy_refresh = vnc_dpy_refresh;
 
     vs->ds->width = 640;